﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Socium.Domain;
using Socium.Domain.Collections;
using Socium.Domain.Persons;
using Socium.Domain.Tests.Sociometric;
using Socium.Presentation;

namespace Socium.Testings.Sociometric {
	class ProcedureViewModel : PageViewModel {
		readonly Procedure _procedure;

		#region Constructor

		public ProcedureViewModel(Database database, Procedure procedure) : base(procedure.Name) {
			Domain.Assertions.Parameters.Assert.NotNull(procedure, "procedure");
			Domain.Assertions.Parameters.Assert.NotNull(database, "database");

			DisplayName = procedure.Name;

			_procedure = procedure;

			var persons = database.Persons;
			Dimension = persons.Count + 1;

			_cells.Add(new StubCellViewModel("topleft") { Column = 0, Row = 0 });

			CreateCriterias(procedure.ElectionCriterias);

			CreateHeaderCells(persons);
			CreateElectionCells(persons);
		}

		#endregion

		#region Cells

		readonly ObservableCollection<CellViewModel> _cells = new ObservableCollection<CellViewModel>();

		public ICollection<CellViewModel> Cells {
			get { return _cells; }
		}

		void CreateHeaderCells(ICollection<Person> persons) {
			_cells.AddRange(persons.MapIndexedLazy((person, index) => CreatePersonCell(person, 0, index + 1)));
			_cells.AddRange(persons.MapIndexedLazy((person, index) => CreatePersonCell(person, index + 1, 0)));
		}

		void CreateElectionCells(ICollection<Person> persons) {
			var dictionary = _criterias.ToDictionary(view_model => view_model.ElectionCriteria);

			var row = 1;
			foreach (var elector in persons) {
				var column = 1;
				foreach (var elected in persons) {
					CellViewModel cell;
					if (elector == elected) {
						cell = new StubCellViewModel(elector.ToString());
					}
					else {
						cell = new ElectionCellViewModel(this, elector, elected, _procedure.Elections, dictionary);
					}

					cell.Row = row;
					cell.Column = column;

					_cells.Add(cell);

					column++;
				}

				row++;
			}
		}

		static PersonCellViewModel CreatePersonCell(Person person, int row, int column) {
			return new PersonCellViewModel(person) { Row = row, Column = column };
		}

		#endregion

		#region Criterias

		readonly ObservableCollection<ElectionCriteriaViewModel> _criterias =
			new ObservableCollection<ElectionCriteriaViewModel>();

		public ICollection<ElectionCriteriaViewModel> Criterias {
			get { return _criterias; }
		}

		public ElectionCriteriaViewModel SelectedCriteria { get; internal set; }

		void CreateCriterias(IEnumerable<ElectionCriteria> criterias) {
			var generator = new ColorGenerator();
			_criterias.AddRange(criterias.MapLazy(criteria => new ElectionCriteriaViewModel(this, criteria) { Color = generator.Next() }));
		}

		#endregion

		public int Dimension { get; private set; }

		#region Elections

		public void Add(Election election) {
			_procedure.Elections.Add(election);
		}

		public void Delete(ElectionViewModel view_model) {
			view_model.Delete(_procedure);
		}

		#endregion
	}
}
